<?php
declare(strict_types=1);

namespace WebApp\lib\db\mongo;

use WebApp\lib\db\AbstractTable;
use WebApp\lib\db\Pool;

/**
 * Class Table
 * @package txz\common\third_lib\model\lib
 */
class MongoTable extends AbstractTable
{
    /**
     * @var MongoDriver
     */
    public $driver;

    public function __construct(IMongoConfig $config, $server_name, $table_name, $pre = '', $suffix = '')
    {
        parent::__construct($server_name, $config->getDbName(), $table_name, $pre, $suffix);
        $this->driver = new MongoDriver($config);
    }

    static function arr2need($need)
    {
        $id_flag = false;

        $option = [];
        if ($need) {
            if ($need instanceof NeedFields) {
                $id_flag = $need->need_id;
                $need = $need->data;
            }
            if (is_object($need)) {
                foreach ($need as $val) $option[$val] = 1;
            } else {
                foreach ($need as $val) $option[$val] = 1;
            }
        }

        if (!$id_flag) {
            $option["_id"] = 0;
        }

        $options = [
            'projection' => $option
        ];
        return $options;
    }

    static function object_to_array($obj) {
        if (is_bool($obj)) return $obj;
        $obj = (array)$obj;
        foreach ($obj as $k => $v) {
            if (gettype($v) == 'resource') {
                return null;
            }
            if (gettype($v) == 'object' || gettype($v) == 'array') {
                $obj[$k] = (array)self::object_to_array($v);
            }
        }
        return $obj;
    }

    public function removeObj($where = [])
    {
        return $this->getPool()->exec(
            $this->driver->remove($this, $where, 1)
        );
    }

    /**
     * @param array $need
     * @param array $where
     * @param string $group
     * @param string $sort
     * @return mixed
     */
    public function getObj($need = [], array $where = [], $group = '', $sort = '')
    {
        $options = self::arr2need($need);
        return self::object_to_array($this->getPool()->exec(
            $this->driver->getObj($this, $where, $options)
        ));

    }

    /**
     * @param array $need
     * @param array $where
     * @param string $group
     * @param string $sort
     * @param string $limit
     * @return mixed
     */
    public function getObjArr($need = [], $where = [], $group = '', $sort = '', $limit = '')
    {
        $options = self::arr2need($need);
        if ($sort) {
            $options['sort'] = $sort;
        }
        if ($limit) {
            $options['limit'] = $limit;
        }
        return self::object_to_array($this->getPool()->exec(
            $this->driver->getObjArr($this, $where, $options)
        ));
    }

    public function updateObj(array $data, array $where, $opt=null, $multi=false, $upsert=false)
    {
        if (!$opt) $opt = '$set';
        if (!$data) return true;
        if (!$where) return false;
        return $this->getPool()->exec(
            $this->driver->update($this, $data, $where, $multi, $upsert, $opt)
        );
    }

    public function addObj(array $data = [])
    {
        if (!$data) return 0;
        return $this->getPool()->exec(
            $this->driver->insert($this, $data)
        );
    }

    /**
     * @return null
     */
    public function getTableName()
    {
        return $this->table_name;
    }

    /**
     * @param null $table_name
     */
    public function setTableName($table_name): void
    {
        $this->table_name = $table_name;
    }

    /**
     * @return null
     */
    public function getDbName()
    {
        return $this->db_name;
    }

    /**
     * @param null $db_name
     */
    public function setDbName($db_name): void
    {
        $this->db_name = $db_name;
    }

    /**
     * @return Pool
     */
    function getPool(): Pool
    {
        if (!$this->pool) {
            $this->pool = new Pool($this->driver);
        }
        return  $this->pool;
    }
}
